<template>
	<view v-if="showPopup" class="uv-popup" :class="[popupClass, isDesktop ? 'fixforpc-z-index' : '']"
		:style="[{ zIndex: zIndex }]">

		<view @touchstart="touchstart">
			<!-- 遮罩层 -->
			<uv-overlay key="1" v-if="maskShow && overlay" :show="showTrans" :duration="duration"
				:custom-style="overlayStyle" :opacity="overlayOpacity" :zIndex="zIndex" @click="onTap"></uv-overlay>
			<uv-transition key="2" :mode="ani" name="content" :custom-style="transitionStyle" :duration="duration"
				:show="showTrans" @click="onTap">
				<view style="border-radius: 20rpx;" class="uv-popup__content" :style="[contentStyle]" :class="[popupClass]"
					@click="clear">
					<uv-status-bar v-if="safeAreaInsetTop"></uv-status-bar>
					<slot />
					<uv-safe-bottom v-if="safeAreaInsetBottom"></uv-safe-bottom>
					<view v-if="closeable" @tap.stop="close" class="uv-popup__content__close"
						:class="['uv-popup__content__close--' + closeIconPos]" hover-class="uv-popup__content__close--hover"
						hover-stay-time="150">
						<uv-icon name="close" color="#909399" size="18" bold></uv-icon>
					</view>
				</view>
			</uv-transition>
		</view>
		<!-- #ifdef H5 -->
		<keypress v-if="maskShow" @esc="onTap" />
		<!-- #endif -->
	</view>
</template>

<script>
// #ifdef H5
import keypress from './keypress.js'
// #endif
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js'
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js'
/**
* PopUp 弹出层
* @description 弹出层组件，为了解决遮罩弹层的问题
* @tutorial https://www.uvui.cn/components/popup.html
* @property {String} mode = [top|center|bottom|left|right] 弹出方式
* 	@value top 顶部弹出
* 	@value center 中间弹出
* 	@value bottom 底部弹出
* 	@value left		左侧弹出
* 	@value right  右侧弹出
* @property {Number} duration 动画时长，默认300
* @property {Boolean} overlay 是否显示遮罩，默认true
* @property {Boolean} overlayOpacity 遮罩透明度，默认0.5 
* @property {Object} overlayStyle 遮罩自定义样式
* @property {Boolean} closeOnClickOverlay = [true|false] 蒙版点击是否关闭弹窗，默认true
* @property {Number | String} zIndex 弹出层的层级
* @property {Boolean} safeAreaInsetTop 是否留出顶部安全区（状态栏高度），默认false
* @property {Boolean} safeAreaInsetBottom 是否为留出底部安全区适配，默认true
* @property {Boolean} closeable 是否显示关闭图标，默认false
* @property {Boolean} closeIconPos 自定义关闭图标位置，`top-left`-左上角，`top-right`-右上角，`bottom-left`-左下角，`bottom-right`-右下角，默认top-right
* @property {String}  bgColor 主窗口背景色
* @property {String}  maskBackgroundColor 蒙版颜色
* @property {Boolean} customStyle 自定义样式
* @event {Function} change 打开关闭弹窗触发，e={show: false}
* @event {Function} maskClick 点击遮罩触发
*/
export default {
	name: 'uv-popup',
	components: {
		// #ifdef H5
		keypress
		// #endif
	},
	mixins: [mpMixin, mixin],
	emits: ['change', 'maskClick'],
	props: {
		// 弹出层类型，可选值，top: 顶部弹出层；bottom：底部弹出层；center：全屏弹出层
		// message: 消息提示 ; dialog : 对话框
		mode: {
			type: String,
			default: 'center'
		},
		// 动画时长，单位ms
		duration: {
			type: [String, Number],
			default: 300
		},
		// 层级
		zIndex: {
			type: [String, Number],
			// #ifdef H5
			default: 997
				// #endif
				// #ifndef H5
				default: 10075
			// #endif
		},
		bgColor: {
			type: String,
			default: '#ffffff'
		},
		safeArea: {
			type: Boolean,
			default: true
		},
		// 是否显示遮罩
		overlay: {
			type: Boolean,
			default: true
		},
		// 点击遮罩是否关闭弹窗
		closeOnClickOverlay: {
			type: Boolean,
			default: true
		},
		// 遮罩的透明度，0-1之间
		overlayOpacity: {
			type: [Number, String],
			default: 0.4
		},
		// 自定义遮罩的样式
		overlayStyle: {
			type: [Object, String],
			default: ''
		},
		// 是否为iPhoneX留出底部安全距离
		safeAreaInsetBottom: {
			type: Boolean,
			default: true
		},
		// 是否留出顶部安全距离（状态栏高度）
		safeAreaInsetTop: {
			type: Boolean,
			default: false
		},
		// 是否显示关闭图标
		closeable: {
			type: Boolean,
			default: false
		},
		// 自定义关闭图标位置，top-left为左上角，top-right为右上角，bottom-left为左下角，bottom-right为右下角
		closeIconPos: {
			type: String,
			default: 'top-right'
		},
		// mode=center，也即中部弹出时，是否使用缩放模式
		zoom: {
			type: Boolean,
			default: true
		},
		round: {
			type: [Number, String],
			default: 0
		},
		...uni.$uv?.props?.popup
	},
	watch: {
		/**
		 * 监听type类型
		 */
		type: {
			handler: function (type) {
				if (!this.config[type]) return
				this[this.config[type]](true)
			},
			immediate: true
		},
		isDesktop: {
			handler: function (newVal) {
				if (!this.config[newVal]) return
				this[this.config[this.mode]](true)
			},
			immediate: true
		},
		// H5 下禁止底部滚动
		showPopup(show) {
			// #ifdef H5
			// fix by mehaotian 处理 h5 滚动穿透的问题
			document.getElementsByTagName('body')[0].style.overflow = show ? 'hidden' : 'visible'
			// #endif
		}
	},
	data() {
		return {
			ani: [],
			showPopup: false,
			showTrans: false,
			popupWidth: 0,
			popupHeight: 0,
			config: {
				top: 'top',
				bottom: 'bottom',
				center: 'center',
				left: 'left',
				right: 'right',
				message: 'top',
				dialog: 'center',
				share: 'bottom'
			},
			transitionStyle: {
				position: 'fixed',
				left: 0,
				right: 0
			},
			maskShow: true,
			mkclick: true,
			popupClass: this.isDesktop ? 'fixforpc-top' : 'top',
			direction: ''
		}
	},
	computed: {
		isDesktop() {
			return this.popupWidth >= 500 && this.popupHeight >= 500
		},
		bg() {
			if (this.bgColor === '' || this.bgColor === 'none' || this.$uv.getPx(this.round) > 0) {
				return 'transparent'
			}
			return this.bgColor
		},
		contentStyle() {
			const style = {};
			if (this.bgColor) {
				style.backgroundColor = this.bg
			}
			if (this.round) {
				const value = this.$uv.addUnit(this.round)
				const mode = this.direction ? this.direction : this.mode
				style.backgroundColor = this.bgColor
				if (mode === 'top') {
					style.borderBottomLeftRadius = value
					style.borderBottomRightRadius = value
				} else if (mode === 'bottom') {
					style.borderTopLeftRadius = value
					style.borderTopRightRadius = value
				} else if (mode === 'center') {
					style.borderRadius = value
				}
			}
			return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
		}
	},
	// #ifndef VUE3
	// TODO vue2
	destroyed() {
		this.setH5Visible()
	},
	// #endif
	// #ifdef VUE3
	// TODO vue3
	unmounted() {
		this.setH5Visible()
	},
	// #endif
	created() {
		// TODO 处理 message 组件生命周期异常的问题
		this.messageChild = null
		// TODO 解决头条冒泡的问题
		this.clearPropagation = false
	},
	methods: {
		setH5Visible() {
			// #ifdef H5
			// fix by mehaotian 处理 h5 滚动穿透的问题
			document.getElementsByTagName('body')[0].style.overflow = 'visible'
			// #endif
		},
		/**
		 * 公用方法，不显示遮罩层
		 */
		closeMask() {
			this.maskShow = false
		},
		// TODO nvue 取消冒泡
		clear(e) {
			// #ifndef APP-NVUE
			e.stopPropagation()
			// #endif
			this.clearPropagation = true
		},

		open(direction) {
			// fix by mehaotian 处理快速打开关闭的情况
			if (this.showPopup) {
				return
			}
			let innerType = ['top', 'center', 'bottom', 'left', 'right', 'message', 'dialog', 'share']
			if (!(direction && innerType.indexOf(direction) !== -1)) {
				direction = this.mode
			} else {
				this.direction = direction;
			}
			if (!this.config[direction]) {
				return this.$uv.error(`缺少类型：${direction}`);
			}
			this[this.config[direction]]()
			this.$emit('change', {
				show: true,
				type: direction
			})
		},
		close(type) {
			this.showTrans = false
			this.$emit('change', {
				show: false,
				type: this.mode
			})
			clearTimeout(this.timer)
			// // 自定义关闭事件
			this.timer = setTimeout(() => {
				this.showPopup = false
			}, 300)
		},
		// TODO 处理冒泡事件，头条的冒泡事件有问题 ，先这样兼容
		touchstart() {
			this.clearPropagation = false
		},
		onTap() {
			if (this.clearPropagation) {
				// fix by mehaotian 兼容 nvue
				this.clearPropagation = false
				return
			}
			this.$emit('maskClick')
			if (!this.closeOnClickOverlay) return
			this.close()
		},
		/**
		 * 顶部弹出样式处理
		 */
		top(type) {
			this.popupClass = this.isDesktop ? 'fixforpc-top' : 'top'
			this.ani = ['slide-top']
			this.transitionStyle = {
				position: 'fixed',
				zIndex: this.zIndex,
				left: 0,
				right: 0,
				backgroundColor: this.bg
			}
			// TODO 兼容 type 属性 ，后续会废弃
			if (type) return
			this.showPopup = true
			this.showTrans = true
			this.$nextTick(() => {
				if (this.messageChild && this.mode === 'message') {
					this.messageChild.timerClose()
				}
			})
		},
		/**
		 * 底部弹出样式处理
		 */
		bottom(type) {
			this.popupClass = 'bottom'
			this.ani = ['slide-bottom']
			this.transitionStyle = {
				position: 'fixed',
				zIndex: this.zIndex,
				left: 0,
				right: 0,
				bottom: 0,
				backgroundColor: this.bg
			}
			// TODO 兼容 type 属性 ，后续会废弃
			if (type) return
			this.showPopup = true
			this.showTrans = true
		},
		/**
		 * 中间弹出样式处理
		 */
		center(type) {
			this.popupClass = 'center'
			this.ani = this.zoom ? ['zoom-in', 'fade'] : ['fade'];
			this.transitionStyle = {
				position: 'fixed',
				zIndex: this.zIndex,
				/* #ifndef APP-NVUE */
				display: 'flex',
				flexDirection: 'column',
				/* #endif */
				bottom: 0,
				left: 0,
				right: 0,
				top: 0,
				justifyContent: 'center',
				alignItems: 'center'
			}
			// TODO 兼容 type 属性 ，后续会废弃
			if (type) return
			this.showPopup = true
			this.showTrans = true
		},
		left(type) {
			this.popupClass = 'left'
			this.ani = ['slide-left']
			this.transitionStyle = {
				position: 'fixed',
				zIndex: this.zIndex,
				left: 0,
				bottom: 0,
				top: 0,
				backgroundColor: this.bg,
				/* #ifndef APP-NVUE */
				display: 'flex',
				flexDirection: 'column'
				/* #endif */
			}
			// TODO 兼容 type 属性 ，后续会废弃
			if (type) return
			this.showPopup = true
			this.showTrans = true
		},
		right(type) {
			this.popupClass = 'right'
			this.ani = ['slide-right']
			this.transitionStyle = {
				position: 'fixed',
				zIndex: this.zIndex,
				bottom: 0,
				right: 0,
				top: 0,
				backgroundColor: this.bg,
				/* #ifndef APP-NVUE */
				display: 'flex',
				flexDirection: 'column'
				/* #endif */
			}
			// TODO 兼容 type 属性 ，后续会废弃
			if (type) return
			this.showPopup = true
			this.showTrans = true
		}
	}
}
</script>
<style lang="less" scoped>
.uv-popup {
	position: fixed;
	/* #ifndef APP-NVUE */
	z-index: 99;

	/* #endif */
	&.top,
	&.left,
	&.right {
		/* #ifdef H5 */
		top: var(--window-top);
		/* #endif */
		/* #ifndef H5 */
		top: 0;
		/* #endif */
	}

	.uv-popup__content {
		/* #ifndef APP-NVUE */
		display: block;
		overflow: hidden;
		/* #endif */
		position: relative;

		&.left,
		&.right {
			/* #ifdef H5 */
			padding-top: var(--window-top);
			/* #endif */
			/* #ifndef H5 */
			padding-top: 0;
			/* #endif */
			flex: 1;
		}

		&__close {
			position: absolute;

			&--hover {
				opacity: 0.4;
			}
		}

		&__close--top-left {
			top: 15px;
			left: 15px;
		}

		&__close--top-right {
			top: 15px;
			right: 15px;
		}

		&__close--bottom-left {
			bottom: 15px;
			left: 15px;
		}

		&__close--bottom-right {
			right: 15px;
			bottom: 15px;
		}
	}
}

.fixforpc-z-index {
	/* #ifndef APP-NVUE */
	z-index: 999;
	/* #endif */
}

.fixforpc-top {
	top: 0;
}
</style>
